package cn.buddha.jesw.mvc.controller;

import cn.buddha.jesw.mvc.service.CommonService;
import com.google.common.base.Stopwatch;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName AsyncController
 * @Author 友野浩二
 * @Date 2019/12/4 12:57
 * @Description Spring MVC 【异步处理 方式一: 使用Callable<>接口】
 * @Version 1.0
 *
 * <pre>
 * Callable接口创建一个子线程用来处理我们的业务，然后直接返回Callable<?>，这样主方法很快就运行完成。
 *
 * 当controller返回值是Callable的时候，SpringMVC就会启动一个线程将Callable交给TaskExecutor去处理，
 * 然后DispatcherServlet还有所有的spring拦截器都退出主线程，然后把response保持打开的状态，
 * 当Callable执行结束之后，SpringMVC就会重新启动分配一个request请求，然后DispatcherServlet就重新调用和处理Callable异步执行的返回结果，
 * 然后返回视图。
 *
 * 【注意】：【请求响应需要等子线程运行完成】
 * </pre>
 */
@RestController
@Slf4j
public class AsyncController {

    @Autowired
    private CommonService commonService;

    @RequestMapping(value = "/async", method = RequestMethod.GET)
    public Callable<String> asyncFun() throws Exception {
        log.info("cn.buddha.jesw.mvc.controller.AsyncController.asyncFun start");

        Stopwatch stopwatch = Stopwatch.createStarted();// 创建自动start的计时器

        Callable<String> result1 = () -> {
            log.info("副线程1开启");
            String str = commonService.taskOne("异步1");
            log.info("副线程1关闭");
            return str;
        };

        Callable<String> result2 = () -> {
            log.info("副线程2开启");
            String str = commonService.taskTwo("异步2");
            log.info("副线程2关闭");
            return str;
        };

        log.info("耗时: {}ms", stopwatch.elapsed(TimeUnit.MILLISECONDS));

        System.out.println("result1: " + result1.call());
        System.out.println("result2: " + result2.call());

        log.info("cn.buddha.jesw.mvc.controller.AsyncController.asyncFun end");
        return result1;
    }

}
